The native-first framework for modern web apps.
A high-performance, zero-VDOM framework that compiles JSX to native DOM. Built with signals and standard Web Components.
Watch a change flow.
Fine-grained signals, no virtual DOM. Edit a value and the update travels only the dependency path it has to — flashing the exact DOM nodes it owns, and nothing else.
Fast where it counts.
The standard js-framework-benchmark operation set vs React, Solid, and Svelte 5 — one shared harness, production builds, 4× CPU throttle. Median ms over 10–12 samples, lower is better.
| Operation | otfw | react | solid | svelte |
|---|---|---|---|---|
| create 1,000 rows | 243.3 | 278.7 | 257.8 | 258.6 |
| create 10,000 rows | 2808.3 | 3389.7 | 2516.3 | 2463.6 |
| append 1,000 to 1,000 | 305.1 | 304.6 | 262.7 | 257.5 |
| update every 10th (1k) | 93.9 | 98.5 | 121 | 88.8 |
| swap 2 rows (1k) | 34.3 | 254.4 | 30.7 | 31.3 |
| select row (1k) | 25.3 | 27.6 | 28.1 | 28.9 |
| remove row (1k) | 38 | 42.1 | 41.5 | 42.1 |
| clear 10,000 rows | 195.2 | 260.7 | 157.7 | 162.4 |
Bold marks a winner only when the margin beats the ~8.3 ms timing resolution — anything closer is a tie. Indicative, not a head-to-head. Run it yourself: bun run bench all.
Cheap to build, too.
What it costs to build a static site — not to run one. Five toolchains, each pre-rendering the same 72 KB MDX docs page. Peak memory and wall time, lower is better.
| Metric | otfw | astro | next | tanstack | vite |
|---|---|---|---|---|---|
| Peak build memory (MB) | 140 | 416 | 1226 | 510 | 260 |
| Build time (s) | 0.3 | 1.2 | 3.8 | 2 | 0.8 |
Not all equal work: astro and vite ship no client JS for these pages, while OTF Web, Next.js and TanStack Start also build a hydration bundle. Read the columns as two runs, not one: ours was re-measured after the build fixes in @opentf/web-compiler, the other four are the original sweep and were not re-run — so treat small gaps as noise. The lead holds up the ladder now (a 2.3 MB page builds in 2.9 s against Astro’s 3.7 s), where it used to reverse past about a megabyte. Method, the full 72 KB→2.3 MB ladder, and every caveat: benchmarks/ssg-build.
Capabilities & roadmap
A transparent look at what ships today and what's next.
Compiler-driven SPA engine.
Direct DOM operations, no diff.
$state, $derived, $effect, $context on fine-grained signals.
$ref to elements; imperative $expose.
Scoped DI with createContext, ContextProvider, and $context — no prop drilling.
Render a subtree into another DOM target; context resolves across the boundary.
Directory routing with client-side navigation.
Persistent UI across route changes.
Protect routes with custom logic + redirects.
Per-route lazy chunks in `otfw build`; dev compiles a route on first visit.
Preload route chunks on hover or when a link enters the viewport.
Pre-render routes to HTML at build time.
MDX pages and components; docs theme included.
Per-request HTML via otfw serve — the same render path as SSG.
First paint adopts the server DOM — pages, layouts, lists, conditionals, and islands with rich props.
App, Docs, or Library templates — JS/TS, auto-install, npm-pinned deps.
On-demand per-route compile. Edits under app/ rebuild and trigger a full-page refresh — not module-level HMR.
Hot-swap changed modules in place without reloading the tab.
In-browser error reporting during dev.
Component testing utilities.
Scaffold .tsx projects with tsconfig and macro typings; full editor tooling in progress.
Component, state, and network inspection.
Compiled by the toolchain — no extra config.
Component-scoped class names.
app/_middleware.js gates pages, API routes, loader data, and SSR — context.locals shared downstream.
getCookie / setCookie / deleteCookie on @opentf/web/server — RFC 6265 helpers for middleware, API routes, and loaders.
@opentf/web-form — porting to the new runtime.
File-based route.js / route.ts endpoints — standard Request/Response and dynamic params.
Route loaders (loader.js → router.data across SSR/SSG/SPA) + client-side resource(); queries and actions planned.
@opentf/web-i18n — URL-prefix locale routing, ICU messages, and Intl formatters (Phase 1).
ARIA helpers and a11y defaults.
Build something native-first.
Scaffold a project in seconds and read the guides to go from zero to a compiled, signal-driven app.